function BangoLogger(){
    var _logEvents = BangoConstants.SETTING_LOGEVENTS();
    var _useOfflineStorage = BangoConstants.SETTING_USEOFFLINESTORAGE();
    var _sessionResumePeriod = BangoConstants.SETTING_SESSION_RESUME_PERIOD();
    var _applicationVersion = "";
    var _applicationType = "";
    var _applicationChannel = "";
    var _userId = "";
    var _postURL = BangoConstants.SETTING_POST_URL();
    var _findLocation = BangoConstants.SETTING_LOCATION_FIND();
    var _userAgent = "";

    var _locationSource = BangoConstants.LOCATION_GPS();
    var _locationLatitude = 0;
    var _locationLongitude = 0;
    var _locationAltitude = 0;
    var _locationAccuracy = 0;

    var _connType = BangoConstants.UNKNOWN_CONNECTION();
    var _opConnType = BangoConstants.UNKNOWN_CONNECTION();
	var connectionTypesSet = false;

    var _applicationId;
    var _isPosting = false;
    var _ajaxPost = null;
    var _profileForPost = null;
	var _postProfilesCount = 0;

    var _userIdKeyName = "BangoStore_UserId";

    var systemServiceObj = null;

    var _networkMode = -1;
	var _operatorName = "";
	var _countryCode = "";

	var networkTransaction = null;
	var connectionStatusTransaction = null;

    var connectionStatusCriteria = {
        Entity: "Connectivity",
        Key: "ConnectionStatus"
    };
    var networkCriteria = {
        Entity: "Network",
        Key: "CurrentNetwork"
    };

    this.logEvents = function(logEvents){
        if (logEvents === undefined) {
            return _logEvents;
        }
        else {
            _logEvents = logEvents;
        }
    };

    this.useOfflineStorage = function(useOfflineStorage){
        if (useOfflineStorage === undefined) {
            return _useOfflineStorage;
        }
        else {
            _useOfflineStorage = useOfflineStorage;
        }
    };

    this.sessionResumePeriod = function(sessionResumePeriod){
        if (sessionResumePeriod === undefined) {
            return _sessionResumePeriod;
        }
        else {
            _sessionResumePeriod = sessionResumePeriod;
        }
    };

    this.applicationVersion = function(applicationVersion){
        if (applicationVersion === undefined) {
            return _applicationVersion;
        }
        else {
            _applicationVersion = applicationVersion;
        }
    };

    this.applicationType = function(applicationType){
        if (applicationType === undefined) {
            return _applicationType;
        }
        else {
            _applicationType = applicationType;
        }
    };

    this.applicationChannel = function(applicationChannel){
        if (applicationChannel === undefined) {
            return _applicationChannel;
        }
        else {
            _applicationChannel = applicationChannel;
        }
    };

    this.userId = function(userId){
        if (userId === undefined) {
            return _userId;
        }
        else {
            _userId = userId;
        }
    };

    this.userAgent = function(userAgent){
        if (userAgent === undefined) {
            return _userAgent;
        }
        else {
            _userAgent = userAgent;
        }
    };

    this.postURL = function(postURL){
        if (postURL === undefined) {
            return _postURL;
        }
        else {
            _postURL = postURL;
        }
    };

    this.findLocation = function(findLocation){
        if (findLocation === undefined) {
            return _findLocation;
        }
        else {
            _findLocation = findLocation;
        }
    };

    this.locationSource = function(locationSource){
        if (locationSource === undefined) {
            return _locationSource;
        }
        else {
            _locationSource = locationSource;
        }
    };

    function setApplicationVersion(){
        //TODO: Set App Version - Not sure if this works so far

		if ((!_applicationVersion)||(_applicationVersion == ""))
		{
			try {
				var appObj = device.getServiceObject("Service.AppManager", "IAppManager");
				var criteria = {
					Type: "UserInstalledPackage"
				};

				var result = appObj.IAppManager.GetList(criteria);

				_applicationVersion = result.Version;
			}
			catch (ex) {
				_applicationVersion = "";
			}
		}
    };

    function setUserId(){
        var userIdString;
		var result;

		if (_userId == "" || _userId == undefined || _userId == null) {
			if (_useOfflineStorage) {
				try {
					userIdString = widget.preferenceForKey(_userIdKeyName);
				}
				catch (ex) {
					userIdString = null;
				}
			}

			if (userIdString == "" || userIdString == undefined || userIdString == null) {
				result = getSysInfoString("Device", "IMEI");

				if (result == "" || result == undefined || result == null) {
					throw "User ID required.";
					return;
				}
				userIdString = calcMD5(result);
			}

			_userId = userIdString;
		}

		if (_useOfflineStorage) {
			try {
				widget.setPreferenceForKey(_userId, _userIdKeyName);
			}
			catch (ex) {
			}
		}

    };

    this.postEvents = function(postCurrentProfile, sendAsync){
        try {
			if (!_isPosting) {
				_isPosting = true;
				if (BangoStorage.bangoStore() != null) {
					for (profileCounter = 0; profileCounter < BangoStorage.bangoStore().length; profileCounter++) {
						if (postCurrentProfile || BangoStorage.bangoStore()[profileCounter].profileId != BangoStorage.profileId()) {
							_profileForPost = new Object();
							_profileForPost.Events = new Array();
							for (eventCounter = 0; eventCounter < BangoStorage.bangoStore()[profileCounter].Events.length; eventCounter++) {
								if (!BangoStorage.bangoStore()[profileCounter].Events[eventCounter].EventPosted &&
									!BangoStorage.bangoStore()[profileCounter].Events[eventCounter].EventIsPosting) {
									BangoStorage.bangoStore()[profileCounter].Events[eventCounter].EventIsPosting = true;
									_profileForPost.Events.push(BangoStorage.bangoStore()[profileCounter].Events[eventCounter]);
								}
							}
							if (_profileForPost.Events.length > 0) {
								for (prop in BangoStorage.bangoStore()[profileCounter]) {
									if (typeof BangoStorage.bangoStore()[profileCounter][prop] != 'object') {
										_profileForPost[prop] = BangoStorage.bangoStore()[profileCounter][prop];
									}
								}
								if (!isRoaming() || isWifi()) {
									postEventsForProfile(JSON.stringify(_profileForPost), sendAsync);
								}
							}
							else {
								BangoStorage.deleteEventsPosted(_useOfflineStorage, BangoStorage.bangoStore()[profileCounter].profileId);
							}
						}
					}
				}
			}
        }
        catch (ex) {
            console.log(ex.message + ":" + ex.line);
        }
        finally {
			_isPosting = false;
        }

    };

    function postEventsForProfile(jsonString, sendAsync){
		var asyncSending;
        try {
			if (_userAgent == null || _userAgent == "" || _userAgent == undefined) {
				_userAgent = navigator.userAgent;
			}

 			asyncSending = true;
			if (sendAsync == false){
				asyncSending = false;
			}

			_ajaxPost = new XMLHttpRequest();
			_ajaxPost.onreadystatechange = onReadyStateChange;
			_ajaxPost.ontimeout = onTimeout;
            _ajaxPost.open("POST", _postURL, asyncSending);
            _ajaxPost.setRequestHeader("User-Agent", _userAgent);
            _ajaxPost.setRequestHeader("Content-Type", "application/json");
            _ajaxPost.setRequestHeader("Content-Length", jsonString.length);
            _ajaxPost.send(jsonString);
		}
        catch (ex) {
            console.log(ex.message + ":" + ex.line);
        }
        finally {
			_isPosting = false;
        }
    };

	function onTimeout(){
		_isPosting = false;
		BangoStorage.clearIsPostingFlag(_useOfflineStorage, _profileForPost);
	};

    function onReadyStateChange(){
        var result;
        try {
            // readyStatus=4 Means completed
            if (_ajaxPost.readyState == 4) {
				/*
				 * get HTTP Data
				 * first check, if there is a response at all,
				 * then if okay, update events to say they have been posted
				 */
                result = _ajaxPost.responseText;
                if (result && result.length > 1 && result.substring(0, 2) == "OK") {
                    updateEventsPosted();
                }
				_isPosting = false;
            }
        }
        catch (ex) {
            console.log(ex.message + ":" + ex.line);
        }

    };

    function updateEventsPosted(){
        BangoStorage.updateEventsPosted(_useOfflineStorage, _profileForPost);
    };

    this.initLogger = function(applicationId){
        _applicationId = applicationId;

        setApplicationVersion();
        setUserId();
		setLocation();

        var manufacturer = getPhoneManufacturer();
        var model = getPhoneModel();
        var productType = getProductType();
        var firmwareVersion = getFirmwareVersion();
        var platformVersion = getPlatformVersion();

        BangoStorage.logProfile(_useOfflineStorage, BangoConstants.SDK_TYPE(), BangoConstants.SDK_VERSION(),
								_applicationId, _applicationType, _applicationChannel, _applicationVersion,
								_userId, _sessionResumePeriod, _connType, isRoaming(),
								_locationSource, _locationAltitude, _locationLatitude, _locationLongitude, _locationAccuracy,
								_operatorName, _operatorName, _countryCode, _operatorName,
								manufacturer, manufacturer, model, productType, firmwareVersion, platformVersion,
								_opConnType);
    };

    function logEventToStore(eventName, errorLevel, eventValue, eventDetail, errorId, eventParameters){
        var returnValue = -1;
        var eventTime = new Date();
        var eventLocalTime = new Date(eventTime.getTime() - (eventTime.getTimezoneOffset() * 60000));

        if (_logEvents) {
            returnValue = BangoStorage.logEvent(_useOfflineStorage, _connType, _opConnType, errorLevel, eventName, eventValue, eventDetail, errorId, eventTime, eventLocalTime, eventParameters);
        }
        return returnValue;
    };

    this.logEvent = function(eventName, eventValue, eventDetail, eventParameters){
        return logEventToStore(eventName, BangoConstants.ERROR_NONE(), eventValue, eventDetail, "", eventParameters);
    };

    this.logEventStart = function(eventValue, eventDetail, eventParameters){
        return this.logEvent(BangoSessionEvents.SESSION_START(), eventValue, eventDetail, eventParameters);
    };

    this.logEventError = function(errorId, message, errorClass, eventParameters){
        return logEventToStore(BangoSessionEvents.EVENT_ERROR(), BangoConstants.ERROR_USER(), errorClass, message, errorId, eventParameters);
    };

    this.logInternalErrorCritical = function(ex){
        return this.logInternalError(ex, BangoConstants.ERROR_INTERNAL_CRITICAL());
    };

    this.logInternalErrorWarning = function(ex){
        return this.logInternalError(ex, BangoConstants.ERROR_INTERNAL_WARNING());
    };

    this.logInternalError = function(ex, errorLevel){
        return logEventToStore("", errorLevel, ex.sourceURL + ":" + ex.line, ex.message, "", null);
    };

	function setLocation(){
		var systemLocationObj;
		var updateoptions;
		var criteria;
		var result;

	    _locationLatitude = 0;
	    _locationLongitude = 0;
	    _locationAltitude = 0;
	    _locationAccuracy = 0;

		if (_findLocation) {
			try {
				// Create System Location Object
				systemLocationObj = device.getServiceObject("Service.Location", "ILocation");

				// Add Location monitor
				updateoptions = new Object();
				updateoptions.PartialUpdates = false;
				criteria = new Object();
				criteria.Updateoptions = updateoptions;
				result = systemLocationObj.ILocation.GetLocation(criteria);
				_locationLatitude = result.ReturnValue.Latitude;
				_locationLongitude = result.ReturnValue.Longitude;
				_locationAltitude = result.ReturnValue.Altitude;
			}
			catch (ex) {

			}
		}
	}

    function connectionStatusChanged(transId, eventCode, result){
		setConnectionTypes(result);
    }

	function setConnectionTypes(result){

        if (result.ErrorCode == 0) {
            var connInfo;

            //if wlan connection is made in offline mode, we get just conninfo object and not the list
            if (result.ReturnValue.ConnectionList) {
                connInfo = result.ReturnValue.ConnectionList.getNext();
            }
            else {
                connInfo = result.ReturnValue;
            }

            if (connInfo != undefined && connInfo.ConnectionType != -1) {
                switch (connInfo.ConnectionType) {
					/*
                    case -1:
                        _connType = BangoConstants.UNKNOWN_CONNECTION();
                        _opConnType = BangoConstants.UNKNOWN_CONNECTION();
                        break;
                    */
                    case 0: // Circuit Switched Data (CSD)  // 9.6 kbit/s
                        _connType = BangoConstants.OPERATOR_CONNECTION();
                        _opConnType = BangoConstants.UNKNOWN_CONNECTION();
                        break;
                    case 1: //Wideband Code Division Multiple Access (WCDMA) //384 Kbps to 2 Mbps
                        _connType = BangoConstants.OPERATOR_CONNECTION();
                        _opConnType = "UMTS";
                        break;
                    case 2: //Local Area Network (LAN) [Emulator]
                    case 7: // Wireless Local Area Network (WLAN)
                    case 8: // Bluetooth
                    case 9: // Virtual VPN
                        _connType = BangoConstants.WIFI_CONNECTION();
                        _opConnType = BangoConstants.UNKNOWN_CONNECTION();
                        break;
                    case 3: // Code Division Multiple Access (CDMA2000) //153 Kbps
                        _connType = BangoConstants.OPERATOR_CONNECTION();
                        _opConnType = "CDMA";
                        break;
                    case 4: // General Packet Radio Service (GPRS) //56-114 kbit/s.
                        _connType = BangoConstants.OPERATOR_CONNECTION();
                        _opConnType = "GPRS";
                        break;
                    case 5: // High Speed Circuit Switched Data (HSCSD) //up to 38.4 kbit/s
                        _connType = BangoConstants.OPERATOR_CONNECTION();
                        _opConnType = BangoConstants.UNKNOWN_CONNECTION();
                        break;
                    case 6: // Enhanced Data rates for Global Evolution (EDGE), Enhanced GPRS (EGPRS) //236.8 kbit/s
                        _connType = BangoConstants.OPERATOR_CONNECTION();
                        _opConnType = "EDGE";
                        rate(4);
                        break;
                    default:
                        _connType = BangoConstants.UNKNOWN_CONNECTION();
                        _opConnType = BangoConstants.UNKNOWN_CONNECTION();
                        break;
                }
            }
            else {
                _connType = BangoConstants.UNKNOWN_CONNECTION();
                _opConnType = BangoConstants.UNKNOWN_CONNECTION();
            }
        }
        else {
            _connType = BangoConstants.UNKNOWN_CONNECTION();
            _opConnType = BangoConstants.UNKNOWN_CONNECTION();
        }

		if (connectionTypesSet == false){
			connectionTypesSet = true;
			BangoStorage.getBatch().OperatorConnectionType = _opConnType;
			BangoStorage.getBatch().ConnectionType = _connType;
		}

	}

    function networkStatusChanged(transId, eventCode, result){
        if (result.ErrorCode == 0) {
            _networkMode = result.ReturnValue.NetworkMode;
			_operatorName = result.ReturnValue.NetworkName;
			_countryCode = result.ReturnValue.CountryCode;
        }

        getInfo(connectionStatusCriteria, connectionStatusChanged);
    }

    function isRoaming(){
        var regStatus = getSysInfo("Network", "RegistrationStatus");
        if (regStatus.ReturnValue.Status == "7") {
            return true;
        }
        else {
            return false;
        }
    };

    function isWifi(){
		return (_connType == BangoConstants.WIFI_CONNECTION)
    };

    function getPhoneManufacturer(){
        return getSysInfoString("Device", "Manufacturer");
    };

    function getPhoneModel(){
        return getSysInfoString("Device", "PhoneModel");
    };

    function getProductType(){
        return getSysInfoString("Device", "ProductType");
    };

    function getPlatformVersion(){
        return getSysInfoString("Device", "PlatformVersion");
    };

    function getFirmwareVersion(){
        return getSysInfoString("Device", "FirmwareVersion");
    };

    function getSysInfoString(entityName, keyName){
        return  getSysInfoString(entityName, keyName, "");
    };

    function loadSysInfoService(){
        try {
			// Create System Service Object
            systemServiceObj = device.getServiceObject("Service.SysInfo", "ISysInfo");

			// Add connection status monitor
            connectionStatusTransaction = systemServiceObj.ISysInfo.GetNotification(connectionStatusCriteria, connectionStatusChanged);
            networkTransaction = systemServiceObj.ISysInfo.GetNotification(networkCriteria, networkStatusChanged);

			// Get current values
            getInfo(connectionStatusCriteria, connectionStatusChanged);
			getInfo(networkCriteria, networkStatusChanged);
        }

        catch (ex) {

        }
    };

	/*
	 * Get system info - Returns requested info string
	 */
    function getSysInfoString(entityName, keyName, defaultReturnValue){
        var result;
        var returnValue;

        try {
            result = getSysInfo(entityName, keyName)
            returnValue = result.ReturnValue.StringData;
            if ((!returnValue) || (returnValue == "")) {
                returnValue = defaultReturnValue;
            }
        }
        catch (ex) {
            returnValue = defaultReturnValue;
        }

        return returnValue;
    };

	/*
	 * Get system -info - Returned requested info Object
	 */
    function getSysInfo(entityName, keyName){
        var result;
        var criteria = new Object();
        criteria.Entity = entityName;
        criteria.Key = keyName;

        try {
            result = systemServiceObj.ISysInfo.GetInfo(criteria);
        }
        catch (ex) {
            result = null;
        }

        return result;
    };

	/*
	 * Set call back method for asynchronous changes in criteria
	 */
	function getInfo(criteria, callback){
		try{
			var res = systemServiceObj.ISysInfo.GetInfo(criteria, callback);
	    }
		catch (ex) {
	    }
	};

	BangoStorage.initStorage(_useOfflineStorage);
    loadSysInfoService();
};
